#define PROJECTION_CONSTANT		0.7
#define INITIAL_CAM_SPEED		0.125

class Camera{
public:
	Point position;
	Point rotation;

	// this transforms from world-space to screen-space
	Transformation screenSpace;

	double move_speed;
	double fovy, aspect, zMin, zMax;
	
	Camera ():
		fovy		(60),
		aspect		(1),
		zMin		(0.5),
		zMax		(10000),
		move_speed	(INITIAL_CAM_SPEED)
	{}

	Camera (double _fovy, double _aspect, double _zMin, double _zMax):
		fovy		(_fovy),
		aspect		(_aspect),
		zMin		(_zMin),
		zMax		(_zMax),
		move_speed	(INITIAL_CAM_SPEED)
	{}

	~Camera(){}

	void setup (double _fovy, double _aspect, double _zMin, double _zMax) {
		fovy = _fovy;
		aspect = _aspect;
		zMin = _zMin;
		zMax = _zMax;
	}
	//
	
	void prepTransformations () {

		////////////////
		// perspective
		glMatrixMode (GL_PROJECTION);
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
		glLoadIdentity();

		float xMin, xMax, yMin, yMax;
		yMax = zMin * tan(fovy * PI / 360.0);
		yMin = -yMax;
		xMin = yMin * aspect;
		xMax = yMax * aspect;
		glFrustum(xMin, xMax, yMin, yMax, zMin, zMax);


		////////////////
		// modelview
		glMatrixMode (GL_MODELVIEW);
		glLoadIdentity();

		glRotated (rotation.x, 1, 0, 0);
		glRotated (rotation.y, 0, 1, 0);
		glTranslated (-position.x, -position.y, -position.z);


		////////////////
		// screen
		int  viewport[4];
		glGetIntegerv(GL_VIEWPORT, viewport);

		screenSpace.setToScale( viewport[2]/2, viewport[3]/2, 0.5 );
		screenSpace.translate( 1, 1, 1 );

		glMatrixMode (GL_PROJECTION);
		Transformation perspective;
		perspective.loadFromStack();
		
		glMatrixMode (GL_MODELVIEW);
		Transformation modelview;
		modelview.loadFromStack();

		screenSpace = screenSpace * perspective * modelview;
	}
	//

	void translate (Vector movement) {
		Transformation T;

		T.setToRotation(-rotation.x, Vector(1,0,0));
		movement = T * movement;

		T.setToRotation(-rotation.y, Vector(0,1,0));
		movement = T * movement;
		
		position += movement;
	}
	//

	void translate (double x, double y, double z) {
		translate( Vector(x, y, z) );
	}

	void rotate (const Vector& _rotation ) {
		rotation += _rotation;

		rotation.x = max(rotation.x, -90);
		rotation.x = min(rotation.x, 90);

		if (rotation.y > 360)
			rotation.y -= 360;
	}

	void rotate (double x, double y, double z) {
		rotate( Vector(x, y, z) );
	}

	// to do: proper orbit functionlity

	// to do: spring-physics floaty camera

};